package xyz.lwm.lazycat.web.exception;


import xyz.lwm.lazycat.utility.ThrowableUtil;
import xyz.lwm.lazycat.web.handle.Context;

import java.util.HashMap;
import java.util.Map;

/**
 * exception mapping
 *
 * @author lwm
 */
public class ExceptionMapperImpl implements ExceptionMapper {

    private final Map<Class<?>, ExceptionHandler<? extends Throwable>> map = new HashMap<>();

    @Override
    public <T extends Throwable> void register(Class<T> exceptionClass, ExceptionHandler<T> exceptionHandler) {
        map.put(exceptionClass, exceptionHandler);
    }

    /**
     * 处理异常
     *
     * @param exception 异常
     * @param ctx       上下文
     */
    public <T extends Throwable> void handle(T exception, Context ctx) {
        ExceptionHandler<T> handler = findByClass(exception);
        if (handler != null) {
            handler.handle(exception, ctx);
        } else {
            ctx.sendError(500, "There is no exception handler registered. " +
                    "You should implement xyz.lwm.lazycat.web.Exceptionable to register " +
                    "xyz.lwm.lazycat.web.exception.ExceptionHandler into " +
                    "xyz.lwm.lazycat.web.exception.ExceptionMapper. \nException strace :\n" +
                    ThrowableUtil.print(exception));
        }
    }

    @SuppressWarnings("unchecked")
    private <T extends Throwable> ExceptionHandler<T> findByClass(T exception) {
        for (Class<?> clz = exception.getClass();
             Exception.class.isAssignableFrom(clz);
             clz = clz.getSuperclass()) {
            if (map.containsKey(clz)) {
                return (ExceptionHandler<T>) map.get(clz);
            }
        }
        return null;
    }

}
